const nsIDownloadBinningRule = Components.interfaces.nsIDownloadBinningRule;
const nsISupports = Components.interfaces.nsISupports;
const CLASS_ID = Components.ID("{556D97B8-B8B4-11DD-9D4C-438E55D89593}");
const CLASS_NAME = "JavaScript XPCOM Component for Download Binning";
const CONTRACT_ID = "@downloadbinning.net/rule;1";

// constructor
function DownloadBinningRule() {
  // initialize data properties
  this.name = "";
  this.description = "";
  this.domain = null;
  this.filename = null;
  this.destination = "";
  this.enabled = true;
}

function DownloadBinningRule(name, description, domain, filename, destination, enabled) {
  this.name = name;
  this.description = description;
  this.domain = domain;
  this.filename = filename;
  this.destination = destination;
  this.enabled = enabled;
}

DownloadBinningRule.prototype = {

  QueryInterface: function(aIID) {
    if (!aIID.equals(nsIDownloadBinningRule) &&    
        !aIID.equals(nsISupports))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  },

  isRegEx: function(regex) {
    return (regex.substring(0,1) == "/") && (regex.substr(regex.length - 1, 1) == "/");
  },
  isDomainRegEx: function() {
    return this.isRegEx(this.domain);
  },
  isFilenameRegEx: function() {
    return this.isRegEx(this.filename);
  },

  getName: function() { return this.name; },
  getDescription: function() { return this.description; },
  getDomain: function() {
    if (this.isRegEx(this.domain)) {
      return this.domain.substring(1, this.domain.length - 1);
    }
    return this.domain;
  },
  getDomainInRaw: function() { return this.domain; },

  getFilename: function() {
    if (this.isRegEx(this.filename)) {
      return this.filename.substring(1, this.filename.length - 1);
    }
    return this.filename;
  },
  getFilenameInRaw: function() { return this.filename; },
  getDestination: function() { return this.destination; },
  getEnabled: function() { return this.enabled; }, // true or false

  getDomainInRegEx: function() {
    if (this.domain == "") return ".*";
    if (this.isRegEx(this.domain)) return this.domain.substring(1, this.domain.length - 1);
    return this.wildcardToRegEx(this.domain);
  },
  getFilenameInRegEx: function() {
    if (this.filename == "") return ".*";
    if (this.isRegEx(this.filename)) return this.filename.substring(1, this.filename.length - 1);
    return this.wildcardToRegEx(this.filename);
  },

  setName: function(name) { this.name = name; },
  setDescription: function(description) { this.description = description; },    
  setDomain: function(domain, isRegEx) { this.domain = isRegEx? "/" + domain + "/" : domain; },
  setFilename: function(filename, isRegEx) { this.filename = isRegEx? "/" + filename + "/" : filename; },      
  setDestination: function(destination) { this.destination = destination; },
  setEnabled: function(value) { this.enabled = value; }, // true or false
  
  wildcardToRegEx: function(wildcard) {
    if (wildcard == null) return null;
    
    var length = wildcard.length;
    var regex_str = "^";

    for (var i = 0; i < length; i++) {
      var c = wildcard.charAt(i);
      switch (c) {
        case '*':
          regex_str += ".*";
          break;
        case '?':
          regex_str += ".";
          break;
          
        // escape characters
        case '(': case ')':
        case '[': case ']':
        case '$':
        case '^':
        case '.':
        case '{': case '}':
        case '|':
        case '\\':
          regex_str += "\\";
          regex_str += c;
          break;
        default:
          regex_str += c;
          break;
      }
    }
    
    regex_str += "$";    
    return regex_str;
  },

}

var DownloadBinningRuleFactory = {
  createInstance: function (aOuter, aIID) {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new DownloadBinningRule()).QueryInterface(aIID);
  }
};

var DownloadBinningRuleModule = {
  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) {
    aCompMgr = aCompMgr.
        QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, 
        CONTRACT_ID, aFileSpec, aLocation, aType);
  },

  unregisterSelf: function(aCompMgr, aLocation, aType) {
    aCompMgr = aCompMgr.
        QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);        
  },
  
  getClassObject: function(aCompMgr, aCID, aIID) {
    if (!aIID.equals(Components.interfaces.nsIFactory))
      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

    if (aCID.equals(CLASS_ID))
      return DownloadBinningRuleFactory;

    throw Components.results.NS_ERROR_NO_INTERFACE;
  },

  canUnload: function(aCompMgr) { return true; }
};

function NSGetModule(aCompMgr, aFileSpec) { return DownloadBinningRuleModule; }
